package com.binance.gateway.filter.auth;

import com.alibaba.fastjson.JSON;
import com.binance.authcenter.api.AuthApi;
import com.binance.authcenter.vo.AuthRequest;
import com.binance.authcenter.vo.AuthResponse;
import com.binance.gateway.app.base.dto.SessionDto;
import com.binance.gateway.app.base.helper.BaseHelper;
import com.binance.gateway.app.base.helper.SessionHelper;
import com.binance.gateway.app.base.vo.CommonRet;
import com.binance.gateway.app.constant.Constant;
import com.binance.gateway.constant.GwFilterOrders;
import com.binance.gateway.util.URIUtil;
import com.binance.master.error.GeneralCode;
import com.binance.master.models.APIRequest;
import com.binance.master.models.APIResponse;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.web.util.WebUtils;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.regex.Pattern;

@Component
@Slf4j
public class PreAuthFilter extends ZuulFilter {
    protected static final String SEND_FORWARD_FILTER_RAN = "sendForwardFilter.ran";
    private Pattern preAuthUrlPattern = Pattern.compile("^(/gateway-api/v\\d+/protect/).*$");
    @Resource
    private SessionHelper sessionHelper;
    @Resource
    private BaseHelper baseHelper;
    @Resource
    private AuthApi authApi;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return GwFilterOrders.PRE_AUTH;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String uri = URIUtil.normalize(ctx.getRequest());
        return preAuthUrlPattern.matcher(uri).matches();
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        if (baseHelper.isFromWeb()) {
            String serialNo = null;
            // Web端登录
            Cookie tokenCookie = WebUtils.getCookie(request, Constant.COOKIE_SERIAL_NO);
            if (tokenCookie != null) {
                serialNo = tokenCookie.getValue();
            } else {
                log.info("serialNo is null");
                halfLoginFail(ctx, true);
                return null;
            }
            APIRequest<AuthRequest> apiAuthRequest = new APIRequest<>();
            AuthRequest body = new AuthRequest();
            body.setSerialNo(serialNo);
            apiAuthRequest.setBody(body);
            APIResponse<AuthResponse> apiAuthResponse = null;
            try {
                apiAuthResponse = authApi.auth(apiAuthRequest);
            } catch (Exception e) {
                log.error("call auth fail", e);
            }
            if (apiAuthResponse != null && apiAuthResponse.getData() != null
                    && apiAuthResponse.getData().getSerialNoValue() != null) {
                ctx.addZuulRequestHeader(Constant.HEADER_USER_EMAIL, apiAuthResponse.getData().getSerialNoValue());
            } else {
                log.info("serialNo auth fail");
                halfLoginFail(ctx, true);
                return null;
            }
        } else {
            // app验证token
            String firstToken = sessionHelper.getAppToken(baseHelper.getClientType(request),
                    request.getParameter("email") + Constant.TOKEN_SECOND_VERIFY);
            if (firstToken == null) {
                halfLoginFail(ctx, false);
                return null;
            }
            ctx.addZuulRequestHeader(Constant.HEADER_USER_EMAIL, request.getParameter("email"));
        }
        return null;
    }

    private void halfLoginFail(RequestContext ctx, boolean isFromWeb) {
        // 半登录态失效的情况下，再次判断用户是否是登录状态
        HttpServletRequest request = ctx.getRequest();
        SessionDto sessionVo = null;
        String token = null;
        if (isFromWeb) {
            // Web端登录
            Cookie tokenCookie = WebUtils.getCookie(request, Constant.COOKIE_TOKEN);
            if (tokenCookie != null) {
                token = tokenCookie.getValue();
            }
            sessionVo = sessionHelper.getSession(token);
            if (sessionVo == null) {
                log.info("halfLoginFail isTokenExpire= {},token={}", sessionVo == null, StringUtils.left(token, Constant.TOKEN_SHOW_LEN));
                authFail(ctx);
                return;
            }
        } else {
            // app验证token
            token = request.getHeader(Constant.HEADER_TOKEN);
            sessionVo = sessionHelper.getSession(token);
            if (sessionVo == null) {
                authFail(ctx);
                return;
            }
        }
        ctx.addZuulRequestHeader(Constant.HEADER_USER_ID, sessionVo.getUserId());
        ctx.addZuulRequestHeader(Constant.HEADER_USER_EMAIL, sessionVo.getEmail());
    }

    private void authFail(RequestContext ctx) {
        ctx.set(SEND_FORWARD_FILTER_RAN, true);
        ctx.setSendZuulResponse(false);
        ctx.setResponseStatusCode(401);
        CommonRet<Void> ret = baseHelper.getCommonRet(GeneralCode.SYS_NOT_LOGIN, ctx.getRequest());
        ctx.setResponseBody(JSON.toJSONString(ret));
    }

}
